﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace ELab.Message
{
    //========================================= FORMAT OF MESSAGE ========================================
    //first byte: message type + 2 next bytes : message package index + message package  + 1 byte checksum
    public class EMessage
    {
        #region Constructor
        public EMessage()
        {

        }

        public EMessage(byte[] data)
        {
            if (data == null || data.Length < 4 || data[0] > 1 || data[1] > 1 || data[2] > 1)
                throw new Exception("Invalidate data bytes of Event message");

            int index = 3; //start Data of the Event
            var endIndex = index;

            //If has Command messager
            if (data[0] == 1)
            {
                // message type
                endIndex += 1;
                var msgTypeBytes = data.Skip(index).Take(1).ToArray();
                index = endIndex;
                if (msgTypeBytes[0] != (byte)MessageType.Command)
                    throw new Exception("Invalidate data bytes of command message");

                // Command type
                endIndex += 1;
                var cmdTypeBytes = data.Skip(index).Take(1).ToArray();
                index = endIndex;
                if (!Enum.IsDefined(typeof(CommandType), cmdTypeBytes[0]))
                    throw new Exception("Invalidate data bytes of command message");

                //get length
                endIndex += 4;
                var msgLengthBytes = data.Skip(index).Take(4).ToArray();
                index = endIndex;
                int length = BitConverter.ToInt32(msgLengthBytes, 0);

                index -= 6;
                endIndex = index + length;
                var msgBodyBytes = data.Skip(index).Take(length).ToArray();
                this.Command = new CommandMessage(msgBodyBytes);
                index = endIndex;
            }

            //If has Event messager
            if (data[1] == 1)
            {
                // message type
                endIndex += 1;
                var msgTypeBytes = data.Skip(index).Take(1).ToArray();
                index = endIndex;
                if (msgTypeBytes[0] != (byte)MessageType.Event)
                    throw new Exception("Invalidate data bytes of Event message");

                //get length
                endIndex += 4;
                var msgLengthBytes = data.Skip(index).Take(4).ToArray();
                index = endIndex;
                int length = BitConverter.ToInt32(msgLengthBytes, 0);


                index -= 5;
                endIndex = index + length;
                var msgBodyBytes = data.Skip(index).Take(length).ToArray();
                this.Event = new EventMessage(msgBodyBytes);
                index = endIndex;
            }

            //If has Screen messager
            if (data[2] == 1)
            {
                // message type
                endIndex += 1;
                var msgTypeBytes = data.Skip(index).Take(1).ToArray();
                index = endIndex;
                if (msgTypeBytes[0] != (byte)MessageType.Screen)
                    throw new Exception("Invalidate data bytes of Screen message");

                //get length
                endIndex += 4;
                var msgLengthBytes = data.Skip(index).Take(4).ToArray();
                index = endIndex;
                int length = BitConverter.ToInt32(msgLengthBytes, 0);

                index -= 5;
                endIndex = index + length;
                var msgBodyBytes = data.Skip(index).Take(length).ToArray();
                this.Screen = new ScreenMessage(msgBodyBytes);
                index = endIndex;
            }
        }
        #endregion

        #region Property
        public ICommandMessage Command { get; set; }

        public IEventMessage Event { get; set; }

        public IScreenMessage Screen { get; set; }

        public byte[] Data
        {
            get
            {
                var _data = new byte[] { 0 /*has command*/, 0/*has event*/, 0/*has screen*/};//3 bytes header

                if (this.Command != null)
                {
                    _data[0] = 1;
                    _data = _data.Append<byte>(this.Command.Data);
                }

                if (this.Event != null)
                {
                    _data[1] = 1;
                    _data = _data.Append<byte>(this.Event.Data);
                }


                if (this.Screen != null)
                {
                    _data[2] = 1;
                    _data = _data.Append<byte>(this.Screen.Data);
                }

                // 1 byte check sum
                byte checksumCalc = Checksum.GetData(_data);
                _data = _data.Append<byte>(checksumCalc);

                return _data;
            }
        }

        public bool IsValidate
        {
            get
            {
                var mydata = this.Data;

                //Dont send no data or invalidate data
                if (mydata == null || mydata.Length < 4) return false;

                //message type is not validate checksum
                byte checksumData = this.Data[this.Data.Length - 1];
                byte checksumCalc = Checksum.GetData(mydata.Take(mydata.Length - 1).ToArray());
                if (checksumCalc != checksumData) return false;

                return true;
            }
        }
        #endregion
    }
}
